import os
import sys
from math import sqrt

import pandas as pd
from numpy import double

import data_input
from data_cal import degrees_to_dmst, degrees_to_ddfm
from four_seven_param_cal import cal_four_seven_param
from gauss_reversals import gauss_forward, gauss_inverse


def write_data(data, file_path, type):
    if type == "Xlsx格式":
        # 将数据写入excel文件，如果文件不存在则创建一个新文件，已存在则覆盖
        # 指定excel文件路径
        excel_path = file_path + '坐标.xlsx'
        # 判断文件是否存在
        if os.path.isfile(excel_path):
            # 文件存在，删除原文件
            os.remove(excel_path)
        # 将数据写入CSV文件
        data.to_excel(excel_path, index=False)
    elif type == "Csv格式":
        # 将数据写入CSV文件，如果文件不存在则创建一个新文件，已存在则覆盖
        # 指定CSV文件路径
        csv_path = file_path + '坐标.csv'
        # 判断文件是否存在
        if os.path.isfile(csv_path):
            # 文件存在，删除原文件
            os.remove(csv_path)
        # 将数据写入CSV文件
        data.to_csv(csv_path, index=False, encoding="utf_8_sig")
    else:
        print("请选择正确的输出格式")


def data_to_file(coor_type, dataframe, BL, XY, folder, file_type, convert_accuracy):
    df_new = pd.DataFrame({'点号': dataframe['点号']})
    match coor_type:
        case "大地坐标":
            df_new['经度'] = BL['经度']
            df_new['纬度'] = BL['纬度']
            df_new['相对误差'] = convert_accuracy
            write_data(df_new, folder + '\BL', file_type)
        case "XY坐标":
            df_new['X坐标'] = XY['X坐标']
            df_new['Y坐标'] = XY['Y坐标']
            df_new['相对误差'] = convert_accuracy
            write_data(df_new, folder + '\XY', file_type)
        case "全选":
            # df_new = pd.DataFrame()
            df_new['经度'] = BL['经度']
            df_new['纬度'] = BL['纬度']
            df_new['X坐标'] = XY['X坐标']
            df_new['Y坐标'] = XY['Y坐标']
            df_new['高程'] = BL['高程']
            df_new['相对误差'] = convert_accuracy
            write_data(df_new, folder + '\BL_XY', file_type)


def add_type_num(whether_need, pj_way, df, central_meridian):
    df_new = pd.DataFrame()
    df_new['X坐标'] = df['X']
    if whether_need == "是" and pj_way == "高斯克吕格投影":
        # 计算六度带编号
        quadrants = int(central_meridian / 6) + 1
        df_new['Y坐标'] = df['Y'].apply(lambda x: str(quadrants) + str(x))
        df_new['高程'] = df['Z']
        return df_new
    elif whether_need == "是" and pj_way == "UTM":
        # 计算六度带编号
        central_meridian = (central_meridian - 31) * 6
        quadrants = int(central_meridian / 6) + 1
        df_new['Y坐标'] = df['Y'].apply(lambda x: str(quadrants) + str(x))
        df_new['高程'] = df['Z']
        return df_new
    else:
        df_new['Y坐标'] = df['Y']
        df_new['高程'] = df['Z']
        return df_new


def output_XY_format(df, xy_format):
    df_new = pd.DataFrame()
    df_new['高程'] = df['Z']
    if xy_format == "度.度格式":
        df_new['经度'] = df['X']
        df_new['纬度'] = df['Y']
        return df_new
    elif xy_format == "度°分′秒″格式":
        df_new['经度'] = df['X'].apply(lambda x: degrees_to_dmst(x))
        df_new['纬度'] = df['Y'].apply(lambda x: degrees_to_dmst(x))
        return df_new
    elif xy_format == "度.分秒格式":
        df_new['经度'] = df['X']
        df_new['纬度'] = df['Y']
        return df_new


def cal_accuracy(xy_data, pj_way, coorSys_text, central_meridian, a, rf):
    PRECISION = 1 / 20000

    df1 = gauss_forward(xy_data, pj_way, coorSys_text, central_meridian, a, rf)

    xy_data2 = pd.DataFrame()
    xy_data2['X'] = xy_data['X']
    xy_data2['Y'] = xy_data['Y'] + 0.0167
    xy_data2['Z'] = xy_data['Z']
    xy_data2 = xy_data2.assign(相对误差=pd.Series([]))

    df2 = gauss_forward(xy_data2, pj_way, coorSys_text, central_meridian, a, rf)
    avg_error = 0
    for index, row in df1.iterrows():
        actual_error = sqrt(
            pow(df1['X'][index] + 1852 - df2['X'][index], 2) + pow(df1['Y'][index] - df2['Y'][index], 2))  # 实际误差
        max_error = sqrt(df1['X'][0] * df1['X'][0] + df1['Y'][0] * df1['Y'][0])  # 最大误差
        avg_error += actual_error / max_error
        xy_data2['相对误差'][index] = round(actual_error / max_error, 10)

    if avg_error <= 1 / 20000:
        print("准换坐标系的相对精度为" + f"{avg_error:.3e}" + "，小于" + f"{PRECISION:.3e}")
    else:
        print("准换坐标系的相对精度为" + f"{avg_error:.3e}" + "，大于" + f"{PRECISION:.3e}")

    return xy_data2['相对误差']


if __name__ == '__main__':
    src_file_path = sys.argv[1]  # 源文件路径
    src_coorSys_text = sys.argv[3]  # 源坐标系文字
    src_central_meridian = double(sys.argv[4])  # 源中央子午线
    src_a = double(sys.argv[5])  # 源长半轴
    src_rf = double(sys.argv[6])  # 源扁率

    tgt_coorSys_text = sys.argv[7]  # 输出坐标系文字
    tgt_central_meridian = double(sys.argv[8])  # 输出中央子午线
    tgt_type_num = sys.argv[9]  # 是否需要带号
    tgt_a = double(sys.argv[10])  # 输出长半轴
    tgt_rf = double(sys.argv[11])  # 输出扁率

    output_file_folder = sys.argv[12]  # 输出文件路径
    output_file_type = sys.argv[13]  # 输出文件的类型  Csv格式  Xlsx格式
    output_coor_type = sys.argv[14]  # 输出坐标类型   大地坐标 XY坐标
    tgt_XY_format = sys.argv[15]  # 输出坐标格式   度.分秒格式  度°分′秒″格式  度.度格式
    four_seven_param_choose = sys.argv[16]  # 四七参数转换

    proj_way = sys.argv[17]  # 投影方式选择  高斯克吕格投影  UTM
    tgt_proj_way = sys.argv[18]  # 投影方式选择  高斯克吕格投影  UTM

    # df = pd.DataFrame(
    #     {'X': [4420445.123, 4364999.332, 4387771], 'Y': [443331.541, 434309.123, 467647], 'Z': [10, 10, 10]})
    df = pd.read_excel('临时坐标.xlsx')
    # 进行高斯反算（文件XY坐标转为经纬度坐标）
    BL_df = gauss_inverse(df, proj_way, src_coorSys_text, src_central_meridian, src_a, src_rf)
    # 判断经纬坐标输出格式
    new_BL_df = output_XY_format(BL_df, tgt_XY_format)
    # 高斯正算，获得XY坐标
    XY_df = gauss_forward(BL_df, tgt_proj_way, tgt_coorSys_text, tgt_central_meridian, tgt_a, tgt_rf)
    # 判断是否需要添加带号
    new_XY_df = add_type_num(tgt_type_num, tgt_proj_way, XY_df, tgt_central_meridian)
    # 计算准换坐标系的经度
    accuracy = cal_accuracy(BL_df, tgt_proj_way, tgt_coorSys_text, tgt_central_meridian, tgt_a, tgt_rf)
    # 四七参数转换
    cal_four_seven_param(four_seven_param_choose, output_file_folder)
    # 写入文件
    data_to_file(output_coor_type, df, new_BL_df, new_XY_df, output_file_folder, output_file_type, accuracy)
    print("输出成功")
